import hashlib

from django.conf import settings
from django.contrib import auth
from django.contrib.auth import login, logout
from django.contrib.auth.hashers import make_password
from django.core.cache import cache
from django.shortcuts import redirect
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.views import TokenRefreshView, TokenObtainPairView

from system.models import Users, Permission, Role, ApiWhiteList
from utils.MyResponse import ErrorResponse, SuccessResponse
from utils.captcha import get_captcha
from utils.myView import CustomView, MixinGetList

from utils.pagination import CustomPagination
from utils.permission import AdminPermission, CustomPermission
from utils.project_url import get_url_method_list, methodList
from utils.request_util import request_save_log
from utils.serializer import CustomModelSerializer


# ------------------------- 登录 -------------------------------------------

from utils.util import selected_chrs
from utils.validator import CustomValidationError, UniqueSerializerValidator


class CaptchaView(APIView):
    """
    tags:
        登录
    get:
        获取验证码
    """
    authentication_classes = []
    permission_classes = []
    filter_backends = []

    def get(self, request, *args, **kwargs):
        data = {}
        if settings.AUTH_CAPTCHA:
            captcha_time = 5*60
            im, code, result = get_captcha()
            # print(code, result)
            while 1:
                key = selected_chrs(6)
                if cache.get('captcha_'+key) is None:
                    break
            cache.set('captcha_'+key, result, captcha_time)
            data = {
                "key": key,
                "image_base": "data:image/png;base64," + im,
            }
        return SuccessResponse(data)


def get_avatar_url(avatar_path):
    """
    获取头像地址
    """
    host = settings.MINIOHTTP + settings.MINIOWEBHOST + ':' + settings.MINIOWEBPORT
    return host + "/" + settings.MINIOPROXY + '/' + avatar_path


class LoginSerializer(TokenObtainPairSerializer):
    """
    登录的序列化器:
    """

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    def validate(self, attrs):
        if settings.AUTH_CAPTCHA:
            captcha = self.initial_data.get("captcha", None)
            captchaKey = self.initial_data.get("captchaKey", None)
            if captcha is None:
                raise CustomValidationError(detail='验证码不能为空')
            cache_captcha = cache.get('captcha_' + captchaKey)
            if cache_captcha is None:
                raise CustomValidationError(detail='验证码过期')
            if str(captcha) != str(cache_captcha):
                raise CustomValidationError(detail='验证码不正确')
            cache.delete('captcha_' + captchaKey)
        data = super().validate(attrs)
        data["user_name"] = self.user.username
        data["user_id"] = self.user.id
        data['avatar_url'] = get_avatar_url(self.user.avatar) if self.user.avatar else self.user.avatar
        request = self.context.get("request")
        request.user = self.user
        request_save_log(request, {'action': '用户登录', 'describe': '用户账号密码登录'})
        return {"code": 1, "msg": "success", "data": data}


class LoginView(TokenObtainPairView):
    """
    tags:
        登录
    """
    serializer_class = LoginSerializer
    authentication_classes = []
    permission_classes = []


# ------------------------- 注册 -------------------------------------------

class UsersSerializer(CustomModelSerializer):

    def validate_password(self, value):
        """
        对密码进行验证
        """
        password = self.initial_data.get("password")
        if password:
            return make_password(value)
        return value

    def validate(self, attrs):

        password = self.initial_data.get("password")
        password1 = self.initial_data.get("password1", None)
        if password1 != password:
            raise CustomValidationError(detail='两次密码不一致', code='manually')

        if settings.AUTH_CAPTCHA:
            captcha = self.initial_data.get("captcha", None)
            captchaKey = self.initial_data.get("captchaKey", None)
            if captcha is None:
                raise CustomValidationError(detail='验证码不能为空', code='manually')
            cache_captcha = cache.get('captcha_' + captchaKey)
            if cache_captcha is None:
                raise CustomValidationError(detail='验证码过期', code='manually')
            if str(captcha) != str(cache_captcha):
                raise CustomValidationError(detail='验证码不正确', code='manually')
            cache.delete('captcha_' + captchaKey)
        data = super().validate(attrs)
        return data

    class Meta:
        model = Users
        fields = ['id', 'username', 'nickname', 'email', 'mobile', 'gender', 'create_datetime', 'role',
                  'password']
        read_only_fields = ['id', 'create_datetime', 'role']
        # extra_kwargs可以重写字段的属性
        extra_kwargs = {
            "password": {"write_only": True},
            "username": {'validators': [UniqueSerializerValidator(queryset=Users.objects.all(), message="账号必须唯一")]},
            "mobile": {'validators': [UniqueSerializerValidator(queryset=Users.objects.all(), message="手机号必须唯一")]},
        }


class RegisterView(CustomView):
    """
    tags:
        注册
    """
    authentication_classes = []
    permission_classes = []

    serializer_class = UsersSerializer

    def create(self, request, *args, **kwargs):
        """
        用户注册
        """
        serializer_class = self.get_serializer_class()
        serializer = serializer_class(data=request.data, request=request)
        serializer.is_valid(raise_exception=True)
        instance = serializer.save()
        token = RefreshToken.for_user(instance)
        data = {
            "access": str(token.access_token),
            "refresh": str(token),
            "user_name": instance.username,
            "user_id": instance.id
        }
        request.user = instance
        request_save_log(request, {'action': '用户注册', 'describe': '用户注册'})
        return SuccessResponse(data)


# ------------------------- 刷新token -------------------------------------------


class CustomTokenRefreshView(TokenRefreshView):
    """
    tags:
        刷新token
    """
    def post(self, request, *args, **kwargs):
        refresh_token = request.data.get("refresh")
        try:
            token = RefreshToken(refresh_token)
            data = {
                "access": str(token.access_token),
                "refresh": str(token)
            }
        except:
            return ErrorResponse(msg='error')
        return SuccessResponse(data=data)


# ------------------------- 权限 -------------------------------------------

class PermissionSerializer(CustomModelSerializer):
    class Meta:
        model = Permission
        fields = '__all__'
        read_only_fields = ['id']


class PermissionView(CustomView):
    """
    tags:
        权限
    """

    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    pagination_class = CustomPagination
    lookup_field = 'pk'


class PermissionAllView(CustomView, MixinGetList):
    """
    tags:
        权限
    get:
        获取所有数据
    """

    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    pagination_class = None

    def get(self, request, *args, **kwargs):
        li = []
        values_list = self.queryset.values_list('value', flat=True).distinct()
        for value in values_list:
            li.append({
                value: self.queryset.filter(value=value).values('id', 'name')
            })
        return SuccessResponse(li, msg='成功')


class UrlListView(CustomView):
    """
    tags:
        权限
    post:
        生成注册的路由权限
    """
    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    pagination_class = None

    def post(self, request, *args, **kwargs):

        url_list = get_url_method_list()
        # print(url_list)
        for item in url_list:
            method_index = methodList.index(item.get('method', 'get'))
            queryset = self.queryset.filter(api=item.get('url'), method=method_index)
            if not queryset.exists():
                Permission.objects.create(
                    api=item.get('url'),
                    method=method_index,
                    name=item.get('name'),
                    value=item.get('value'),
                )
            # else:
            #     queryset.update(
            #         name=item.get('name'),
            #         value=item.get('value'),
            #     )

        return SuccessResponse(None, msg='成功')


# ------------------------- 角色 -------------------------------------------


class RoleSerializer(CustomModelSerializer):

    permission_list = serializers.SerializerMethodField(required=False)

    def get_permission_list(self, instance):
        li = []
        if self.request and self.request.method == 'GET':
            values_list = instance.permission.all().values_list('value', flat=True).distinct()
            for value in values_list:
                li.append({
                    value: instance.permission.all().filter(value=value).values('id', 'name')
                })
        return li

    class Meta:
        model = Role
        fields = '__all__'
        read_only_fields = ['id']


class RoleView(CustomView):
    """
    tags:
        角色
    """

    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    pagination_class = CustomPagination
    lookup_field = 'pk'


class RoleAllView(CustomView, MixinGetList):
    """
    tags:
        角色
    get:
        获取所有数据
    """

    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = Role.objects.all()
    serializer_class = RoleSerializer

# ------------------------- 用户列表 -------------------------------------------


class UserListSerializer(CustomModelSerializer):
    def validate_password(self, value):
        """
        对密码进行验证
        """
        password = self.initial_data.get("password")
        if password:
            return make_password(value)
        return value

    class Meta:
        model = Users
        fields = ['id', 'username', 'nickname', 'email', 'mobile', 'gender', 'create_datetime', 'role',
                  'password']
        read_only_fields = ['id', 'create_datetime']
        # extra_kwargs可以重写字段的属性
        extra_kwargs = {
            "password": {"write_only": True},
        }


class UserListUpdateSerializer(CustomModelSerializer):
    def validate_password(self, value):
        """
        对密码进行验证
        """
        password = self.initial_data.get("password")
        if password:
            return make_password(value)
        return value

    class Meta:
        model = Users
        fields = ['id', 'username', 'nickname', 'email', 'mobile', 'gender', 'create_datetime', 'role',
                  'password']
        read_only_fields = ['id', 'create_datetime']
        # extra_kwargs可以重写字段的属性
        extra_kwargs = {
            "password": {"write_only": True, 'required': False},
            "username": {'required': False},
        }


class UserListView(CustomView):
    """
    tags:
        用户列表
    """
    permission_classes = [IsAuthenticated, AdminPermission]
    queryset = Users.objects.all()
    serializer_class = UserListSerializer
    pagination_class = CustomPagination
    lookup_field = 'pk'

    keys = openapi.Schema(description='主键列表', type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER))

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['keys'],
        properties={'keys': keys}
    ))
    def multiple_destroy(self, request, *args, **kwargs):
        """
        删除数据


        删除数据，传入的是数组，表示可以删除多条
        """
        queryset = self.filter_queryset(self.get_queryset())
        queryset = queryset.filter(id__in=request.data.get('keys', []))
        if queryset.exists():
            for instance in queryset:
                if request.user.is_superuser is False:
                    is_superuser = instance.is_superuser
                    is_admin = instance.role.values_list('admin', flat=True)
                    if is_superuser or True in is_admin or instance.id == request.user.id:
                        return ErrorResponse(None, msg=f'您没有权限删除用户：{instance.username}')
                else:
                    if instance.id == request.user.id:
                        return ErrorResponse(None, msg=f'您不能删除自己')

            queryset.delete()
            return SuccessResponse(None, msg='删除成功')
        else:
            return ErrorResponse(None, msg='未找到数据')


class UserUpdateListView(CustomView):
    """
    tags:
        用户列表
    """
    permission_classes = [IsAuthenticated, AdminPermission]
    queryset = Users.objects.all()
    serializer_class = UserListUpdateSerializer
    lookup_field = 'pk'


# ------------------------- 接口白名单 -------------------------------------------


class ApiWhiteListSerializer(CustomModelSerializer):
    class Meta:
        model = ApiWhiteList
        fields = '__all__'
        read_only_fields = ['id']


class ApiWhiteListView(CustomView):
    """
    tags:
        接口白名单
    """

    permission_classes = [IsAuthenticated, AdminPermission]

    queryset = ApiWhiteList.objects.all()
    serializer_class = ApiWhiteListSerializer
    pagination_class = CustomPagination
    lookup_field = 'pk'


class ApiLoginSerializer(CustomModelSerializer):
    """接口文档登录-序列化器"""

    username = serializers.CharField()
    password = serializers.CharField()

    class Meta:
        model = Users
        fields = ["username", "password"]


class ApiLogin(APIView):
    """接口文档的登录接口"""

    serializer_class = ApiLoginSerializer
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        username = request.data.get("username")
        password = request.data.get("password")
        user_obj = auth.authenticate(
            request,
            username=username,
            password=password,
        )
        if user_obj:
            login(request, user_obj)
            return redirect("/")
        else:
            return ErrorResponse(msg="账号/密码错误")


class ApiLogout(APIView):
    """接口文档的登录接口"""

    def post(self, request):

        if request.user:
            logout(request)
            return redirect("/")
        else:
            return ErrorResponse(msg="会话错误")

